﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "DataSchemaPrivate.h"
#include "GbmpQuickCast.h"
#include "ClassId.h"

// TODO: chenpy-a 2020/01/24 放在这里不合适
#ifdef EMSCRIPTEN
#define TR_MODULE_NAME L""
#endif

//////////////////////////////////////////////////////////////////////////
// 声明没有数据成员的类，等同于DATA_BEGIN/DATA_END中间没有内容。
// 用于继承于NdbObject的接口（没有数据成员的类）。
#define DECLARE_CLASS_WITHOUT_DATA_MEMBERS(NS_PREFIX, CLASS_NAME, PARENT_NAME,CLASS_ID,MODULE_NS_PREFIX) \
    DEFINE_CAST_DERIVED(NS_PREFIX::CLASS_NAME, PARENT_NAME); \
public: \
    typedef PARENT_NAME Super; \
    typedef CLASS_NAME Self; \
    static const gcmp::ClassId & GetClassId() { static gcmp::ClassId s_classId(WSTRING_OF(CLASS_ID)); return s_classId; } \
    static gcmp::NdbClassSchema* ms_pNdbClassSchema; \
    FORCE_INLINE static gcmp::NdbClassSchema* GetStaticClassSchema() { return ms_pNdbClassSchema; }   \
    static void AddNdbSchema() \
    {   \
        NDB_CHECK_RELATIONSHIP(NS_PREFIX::CLASS_NAME, PARENT_NAME);\
        NDB_CHECK_FULL_NAMESPACE(NS_PREFIX::CLASS_NAME);\
        NDB_CHECK_FULL_NAMESPACE(PARENT_NAME);\
        ms_pNdbClassSchema = gcmp::NdbClassSchemaLibraryOfCode::GetInstance()->CreateClassSchema( \
            Super::GetClassId(), \
            GetClassId(), \
            WSTRING_OF(PARENT_NAME), \
            WSTRING_OF(CLASS_NAME), \
            nullptr,\
            MODULE_NS_PREFIX::MODULE_ID, \
            TR_MODULE_NAME, \
            sizeof(CLASS_NAME) \
        );\
    };

//////////////////////////////////////////////////////////////////////////
// 定义没有数据成员的类，比DATA_DEFINE少提供一个构造函数体。
// 用于继承于NdbObject的接口（没有数据成员的类）。
#define DEFINE_CLASS_WITHOUT_DATA_MEMBERS(CLASS_NAME) \
    gcmp::NdbClassSchema* CLASS_NAME::ms_pNdbClassSchema = nullptr; \
    class Ndb##CLASS_NAME##AddSchema {    \
    public:                                                    \
        Ndb##CLASS_NAME##AddSchema();                            \
    };                                                        \
    static Ndb##CLASS_NAME##AddSchema _##Ndb##CLASS_NAME##AddSchema; \
    Ndb##CLASS_NAME##AddSchema::Ndb##CLASS_NAME##AddSchema()    \
    {   \
        CLASS_NAME::AddNdbSchema();     \
    }

#define DATA_BEGIN(NS_PREFIX, CLASS_NAME, PARENT_NAME, CLASS_ID, MODULE_NS_PREFIX)               \
    DEFINE_CAST_DERIVED(NS_PREFIX::CLASS_NAME, PARENT_NAME); \
    DATA_BEGIN_IMP(NS_PREFIX, CLASS_NAME, PARENT_NAME, CLASS_ID, MODULE_NS_PREFIX)

#define DATA_BEGIN_AND_QUICK_CAST_FROM(NS_PREFIX, CLASS_NAME, PARENT_NAME, CLASS_ID, MODULE_NS_PREFIX, QUICK_CAST_SOURCE)               \
    DEFINE_CAST_DERIVED2(NS_PREFIX::CLASS_NAME,PARENT_NAME, QUICK_CAST_SOURCE); \
    DATA_BEGIN_IMP(NS_PREFIX, CLASS_NAME, PARENT_NAME, CLASS_ID, MODULE_NS_PREFIX)

#define DATA_END    };

#define DATA_DEFINE(CLASS_NAME) \
    gcmp::NdbClassSchema* CLASS_NAME::ms_pNdbClassSchema = nullptr; \
    class Ndb##CLASS_NAME##AddSchema {    \
    public:                                                    \
        Ndb##CLASS_NAME##AddSchema();                            \
    };                                                        \
    static Ndb##CLASS_NAME##AddSchema _##Ndb##CLASS_NAME##AddSchema; \
    Ndb##CLASS_NAME##AddSchema::Ndb##CLASS_NAME##AddSchema()    \
    {   \
        CLASS_NAME::AddNdbSchema();     \
    } \
    gcmp::OwnerPtr<gcmp::NdbObject> CLASS_NAME::CreateNdbObject()    \
    { \
        void *pMem = ::operator new(sizeof(CLASS_NAME)); \
        if (pMem) \
        { \
        memset(pMem, '\0', sizeof(CLASS_NAME)); \
        new (pMem) CLASS_NAME(); \
        } \
        CLASS_NAME *pObj = (CLASS_NAME*)pMem; \
        return gcmp::OwnerPtr<CLASS_NAME>(pObj); \
    } \
    CLASS_NAME::CLASS_NAME() { InitializeObject(); } \
    void CLASS_NAME::InitializeObject()
